package com.jeesite.modules.service;

import com.jeesite.common.service.CrudService;
import com.jeesite.modules.dao.DonationRecordDao;
import com.jeesite.modules.dao.PaymentOrderDao;
import com.jeesite.modules.entity.DonationRecord;
import com.jeesite.modules.entity.PaymentOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

/**
 * 捐赠服务类
 * @author LaVenderGong
 * @version 2025-08-16
 */
@Service
@Transactional(readOnly = true)
public class DonationService extends CrudService<DonationRecordDao, DonationRecord> {

    @Autowired
    private PaymentOrderDao paymentOrderDao;

    /**
     * 预创建捐赠记录（用于支付流程）
     */
    @Transactional(readOnly = false)
    public DonationRecord preCreateDonation(DonationRecord donation) {
        try {
            // 设置默认值
            donation.setDonateDate(new Date());
            donation.setPaymentStatus(DonationRecord.STATUS_PENDING);

            // 生成唯一的支付订单号
            String paymentOrderId = generatePaymentOrderId();
            donation.setPaymentOrderId(paymentOrderId);

            // 如果没有提供游戏昵称但有游戏账号ID，可以在这里查询游戏昵称
            // 目前先直接使用传入的值，后续可以集成游戏账号系统

            // 保存捐赠记录（预创建状态）
            try {
                logger.info("准备保存捐赠记录，使用DAO直接插入");
                dao.insert(donation);
                logger.info("捐赠记录插入完成，返回的ID: {}, 订单号: {}", donation.getId(), paymentOrderId);

                // 如果ID仍然为null，尝试通过订单号查询获取ID
                if (donation.getId() == null || donation.getId().isEmpty()) {
                    logger.warn("插入后ID为空，尝试通过订单号查询获取ID");
                    DonationRecord savedDonation = dao.findByPaymentOrderId(paymentOrderId);
                    if (savedDonation != null) {
                        donation.setId(savedDonation.getId());
                        logger.info("通过订单号查询获取到ID: {}", donation.getId());
                    } else {
                        logger.error("无法通过订单号查询到刚插入的记录");
                    }
                }

                logger.info("捐赠记录保存成功，最终ID: {}, 订单号: {}", donation.getId(), paymentOrderId);
            } catch (Exception e) {
                logger.error("保存捐赠记录失败", e);
                throw e;
            }

            // 创建对应的支付订单（在保存donation后，确保有ID）
            try {
                logger.info("开始创建支付订单，捐赠ID: {}, 支付方式: {}", donation.getId(), donation.getPaymentMethod());
                boolean success = createPaymentOrderSimple(donation, donation.getPaymentMethod());
                if (success) {
                    logger.info("支付订单创建成功，订单ID: {}", donation.getPaymentOrderId());
                } else {
                    logger.error("支付订单创建失败，订单ID: {}", donation.getPaymentOrderId());
                }
            } catch (Exception e) {
                logger.error("创建支付订单失败，但捐赠记录已保存: " + e.getMessage(), e);
                // 不抛出异常，让捐赠记录创建成功
            }

            return donation;
        } catch (Exception e) {
            logger.error("预创建捐赠记录失败", e);
            throw e;
        }
    }

    /**
     * 创建捐赠记录
     */
    @Transactional(readOnly = false)
    public DonationRecord createDonation(DonationRecord donation) {
        // 设置默认值
        donation.setDonateDate(new Date());
        donation.setPaymentStatus(DonationRecord.STATUS_PENDING);

        // 生成唯一的支付订单号
        String paymentOrderId = generatePaymentOrderId();
        donation.setPaymentOrderId(paymentOrderId);

        // 如果没有提供游戏昵称但有游戏账号ID，可以在这里查询游戏昵称
        // 目前先直接使用传入的值，后续可以集成游戏账号系统

        // 保存捐赠记录
        save(donation);

        return donation;
    }

    /**
     * 创建支付订单
     */
    @Transactional(readOnly = false)
    public boolean createPaymentOrderSimple(DonationRecord donation, String paymentMethod) {
        logger.info("开始创建支付订单，donation ID: {}, paymentOrderId: {}, paymentMethod: {}",
                   donation.getId(), donation.getPaymentOrderId(), paymentMethod);

        // 直接使用基本类型，避免实体类的循环引用问题
        String orderId = donation.getPaymentOrderId();
        Long donationId = null;

        // 安全地设置donationId，避免空指针异常
        if (donation.getId() != null && !donation.getId().isEmpty()) {
            try {
                donationId = Long.valueOf(donation.getId());
                logger.info("设置donation ID: {}", donationId);
            } catch (NumberFormatException e) {
                logger.warn("无法转换donation ID为Long: " + donation.getId(), e);
                donationId = null;
            }
        } else {
            logger.warn("donation ID为空，设置为null");
            donationId = null;
        }

        logger.info("准备插入支付订单，订单信息: orderId={}, donationId={}, amount={}, paymentMethod={}",
                   orderId, donationId, donation.getAmount(), paymentMethod);

        try {
            // 使用原生插入方法，避免StackOverflowError
            int result = paymentOrderDao.insertPaymentOrder(
                orderId,
                donationId,
                paymentMethod,
                donation.getAmount(),
                PaymentOrder.STATUS_CREATED,
                new Date()
            );

            if (result > 0) {
                logger.info("支付订单插入成功，订单ID: {}, 影响行数: {}", orderId, result);
                return true;
            } else {
                logger.error("支付订单插入失败，影响行数为0，订单ID: {}", orderId);
                return false;
            }
        } catch (Exception e) {
            logger.error("支付订单插入失败，订单ID: " + orderId, e);
            throw e;
        }
    }

    /**
     * 创建捐赠记录和支付订单（带完整用户信息）
     */
    @Transactional(readOnly = false)
    public boolean createDonationAndPaymentOrder(String orderId, BigDecimal amount, String donorName, String subject, String paymentMethod,
                                                String gameAccountId, String gameNickname, String contactInfo) {
        try {
            logger.info("开始创建捐赠记录和支付订单，订单号: {}, 金额: {}, 捐赠者: {}, 游戏账号: {}", orderId, amount, donorName, gameAccountId);

            // 创建捐赠记录
            int donationResult = dao.insertDonationRecord(
                orderId,           // paymentOrderId
                amount,           // amount
                donorName,        // donorName
                subject,          // message
                DonationRecord.STATUS_PENDING,  // paymentStatus
                new Date(),       // donateDate
                gameAccountId,    // gameAccountId
                gameNickname,     // gameNickname
                contactInfo       // contactInfo
            );

            if (donationResult <= 0) {
                logger.error("创建捐赠记录失败，订单号: {}", orderId);
                return false;
            }

            logger.info("成功创建捐赠记录，订单号: {}, 影响行数: {}", orderId, donationResult);

            // 查询刚创建的捐赠记录以获取 ID
            DonationRecord createdDonation = dao.findByPaymentOrderId(orderId);
            Long donationId = null;
            if (createdDonation != null) {
                try {
                    donationId = Long.parseLong(createdDonation.getId());
                    logger.info("获取到捐赠记录 ID: {}", donationId);
                } catch (NumberFormatException e) {
                    logger.warn("无法解析捐赠记录 ID: {}", createdDonation.getId());
                }
            } else {
                logger.warn("无法获取捐赠记录 ID，订单号: {}", orderId);
            }

            // 创建支付订单
            int paymentResult = paymentOrderDao.insertPaymentOrder(
                orderId,                        // orderId
                donationId,                    // donationId
                paymentMethod,                 // paymentMethod
                amount,                        // amount
                PaymentOrder.STATUS_CREATED,   // status
                new Date()                     // createTime
            );

            if (paymentResult <= 0) {
                logger.error("创建支付订单失败，订单号: {}", orderId);
                return false;
            }

            logger.info("成功创建支付订单，订单号: {}, 影响行数: {}", orderId, paymentResult);
            logger.info("成功创建捐赠记录和支付订单，订单号: {}", orderId);
            return true;

        } catch (Exception e) {
            logger.error("创建捐赠记录和支付订单时发生异常，订单号: {}", orderId, e);
            return false;
        }
    }

    /**
     * 创建捐赠记录和支付订单（简化版本，向后兼容）
     */
    @Transactional(readOnly = false)
    public boolean createDonationAndPaymentOrder(String orderId, BigDecimal amount, String donorName, String subject, String paymentMethod) {
        return createDonationAndPaymentOrder(orderId, amount, donorName, subject, paymentMethod, null, null, null);
    }



    /**
     * 处理支付成功回调
     */
    @Transactional(readOnly = false)
    public boolean handlePaymentSuccess(String orderId, String transactionId, String callbackData) {
        try {
            logger.info("开始处理支付成功回调，订单号: {}, 交易号: {}", orderId, transactionId);

            // 直接更新支付订单状态，避免查询实体类
            logger.info("开始更新支付订单状态，订单号: {}", orderId);

            try {
                Date payTime = new Date();
                logger.info("准备更新支付订单状态，订单号: {}, 支付时间: {}", orderId, payTime);

                int updateResult = paymentOrderDao.updatePaymentOrderStatus(
                    orderId,
                    PaymentOrder.STATUS_SUCCESS,
                    payTime,
                    transactionId,
                    callbackData
                );

                logger.info("支付订单更新结果，影响行数: {}", updateResult);

                if (updateResult > 0) {
                    logger.info("支付订单状态更新成功，订单号: {}, 影响行数: {}", orderId, updateResult);
                } else {
                    logger.error("支付订单状态更新失败，订单号: {}，可能订单不存在", orderId);
                    return false;
                }
            } catch (Exception e) {
                logger.error("更新支付订单状态时发生异常，订单号: {}", orderId, e);
                return false;
            }

            // 直接更新捐赠记录状态，避免查询实体类
            logger.info("开始更新捐赠记录状态，订单号: {}", orderId);

            try {
                int donationUpdateResult = dao.updateDonationStatus(
                    orderId,
                    DonationRecord.STATUS_PAID,
                    transactionId,
                    new Date()
                );

                logger.info("捐赠记录更新结果，影响行数: {}", donationUpdateResult);

                if (donationUpdateResult > 0) {
                    logger.info("捐赠记录状态更新成功，订单号: {}, 新状态: {}, 影响行数: {}",
                               orderId, DonationRecord.STATUS_PAID, donationUpdateResult);
                } else {
                    logger.error("捐赠记录状态更新失败，订单号: {}，可能订单不存在", orderId);
                    return false;
                }
            } catch (Exception e) {
                logger.error("更新捐赠记录状态时发生异常，订单号: {}", orderId, e);
                return false;
            }

            return true;
        } catch (Exception e) {
            logger.error("处理支付成功回调失败，订单号: " + orderId, e);
            return false;
        }
    }

    /**
     * 处理支付失败回调
     */
    @Transactional(readOnly = false)
    public boolean handlePaymentFailed(String orderId, String reason) {
        try {
            // 更新支付订单状态
            paymentOrderDao.updatePaymentOrderStatus(
                orderId,
                PaymentOrder.STATUS_FAILED,
                null,
                null,
                reason
            );
            
            // 更新捐赠记录状态
            DonationRecord donation = dao.findByPaymentOrderId(orderId);
            if (donation != null) {
                donation.setPaymentStatus(DonationRecord.STATUS_FAILED);
                update(donation);
            }
            
            return true;
        } catch (Exception e) {
            logger.error("处理支付失败回调失败", e);
            return false;
        }
    }

    /**
     * 获取捐赠统计信息
     */
    public Map<String, Object> getDonationStatistics() {
        Map<String, Object> statistics = dao.getDonationStatistics();
        
        // 添加额外统计信息
        statistics.put("recentDonations", dao.getRecentDonations(10));
        statistics.put("paymentMethodStats", dao.getPaymentMethodStatistics());
        statistics.put("monthlyStats", dao.getMonthlyStatistics());
        
        return statistics;
    }

    /**
     * 获取捐赠排行榜
     */
    public List<Map<String, Object>> getDonationRanking(int limit) {
        return dao.getDonationRanking(limit);
    }

    /**
     * 获取感谢名单（用于前端展示）
     */
    public Map<String, Object> getThanksList(int page, int size) {
        // 获取总记录数
        int totalCount = dao.getPaidDonationsCount();
        logger.info("获取感谢名单 - 总记录数: {}, 页码: {}, 每页大小: {}", totalCount, page, size);

        // 计算偏移量
        int offset = (page - 1) * size;

        // 分页查询记录
        List<DonationRecord> records = dao.getPaidDonationsWithPaging(size, offset);
        logger.info("获取感谢名单 - 实际查询到记录数: {}", records.size());

        List<Map<String, Object>> thanksList = new ArrayList<>();
        for (DonationRecord record : records) {
            Map<String, Object> item = new HashMap<>();
            // 优先显示游戏昵称，其次是捐赠者姓名，最后是匿名
            String displayName = record.getGameNickname();
            if (displayName == null || displayName.trim().isEmpty()) {
                displayName = record.getDonorName();
            }
            if (displayName == null || displayName.trim().isEmpty()) {
                displayName = "匿名用户";
            }

            item.put("displayName", displayName);
            item.put("gameNickname", record.getGameNickname());
            item.put("donorName", record.getDonorName());
            item.put("amount", record.getAmount());
            item.put("donateDate", record.getDonateDate());
            item.put("message", record.getMessage());
            item.put("paymentMethod", record.getPaymentMethod());

            thanksList.add(item);
        }

        Map<String, Object> response = new HashMap<>();
        response.put("list", thanksList);
        response.put("total", totalCount); // 使用实际的总记录数
        response.put("page", page);
        response.put("size", size);
        response.put("totalPages", (int) Math.ceil((double) totalCount / size));

        return response;
    }

    /**
     * 获取捐赠配置
     */
    public Map<String, Object> getDonationConfig() {
        Map<String, Object> config = new HashMap<>();
        
        // 预设金额
        List<BigDecimal> presetAmounts = Arrays.asList(
            new BigDecimal("5.00"),
            new BigDecimal("10.00"),
            new BigDecimal("20.00"),
            new BigDecimal("50.00"),
            new BigDecimal("100.00"),
            new BigDecimal("200.00")
        );
        config.put("presetAmounts", presetAmounts);
        
        // 金额限制
        config.put("minAmount", new BigDecimal("1.00"));
        config.put("maxAmount", new BigDecimal("10000.00"));
        
        // 支持的支付方式
        List<Map<String, String>> paymentMethods = new ArrayList<>();
        paymentMethods.add(createPaymentMethod("alipay", "支付宝", "alipay.png"));
        paymentMethods.add(createPaymentMethod("wechat", "微信支付", "wechat.png"));
        paymentMethods.add(createPaymentMethod("unionpay", "云闪付", "unionpay.png"));
        config.put("paymentMethods", paymentMethods);
        
        // 捐赠说明
        config.put("description", "感谢您对KBB服务器的支持！您的捐赠将用于服务器维护和功能改进。");
        
        return config;
    }

    /**
     * 生成支付订单号
     */
    private String generatePaymentOrderId() {
        return "DN" + System.currentTimeMillis() + String.format("%04d", new Random().nextInt(10000));
    }

    /**
     * 创建支付方式配置
     */
    private Map<String, String> createPaymentMethod(String code, String name, String icon) {
        Map<String, String> method = new HashMap<>();
        method.put("code", code);
        method.put("name", name);
        method.put("icon", icon);
        return method;
    }

    /**
     * 处理超时订单
     */
    @Transactional(readOnly = false)
    public void handleTimeoutOrders() {
        // 将30分钟前创建但未支付的订单标记为失败
        int timeoutMinutes = 30;
        List<PaymentOrder> timeoutOrders = paymentOrderDao.findTimeoutOrders(timeoutMinutes);
        
        for (PaymentOrder order : timeoutOrders) {
            handlePaymentFailed(order.getOrderId(), "支付超时");
        }
        
        logger.info("处理超时订单完成，共处理 {} 个订单", timeoutOrders.size());
    }

    /**
     * 获取调试信息
     */
    public Map<String, Object> getDebugInfo() {
        Map<String, Object> debugInfo = new HashMap<>();

        // 获取总记录数
        int totalCount = dao.getPaidDonationsCount();
        debugInfo.put("totalPaidCount", totalCount);

        // 获取所有状态的记录数
        int allCount = dao.getAllDonationsCount();
        debugInfo.put("totalAllCount", allCount);

        // 获取所有记录的支付状态统计
        List<DonationRecord> allRecords = dao.getAllDonations();
        Map<String, Integer> statusCount = new HashMap<>();
        for (DonationRecord record : allRecords) {
            String status = record.getPaymentStatus();
            statusCount.put(status, statusCount.getOrDefault(status, 0) + 1);
        }
        debugInfo.put("statusStatistics", statusCount);

        // 获取前20条记录的详细信息（包括所有状态）
        List<Map<String, Object>> recordDetails = new ArrayList<>();
        for (DonationRecord record : allRecords) {
            Map<String, Object> detail = new HashMap<>();
            detail.put("id", record.getId());
            detail.put("donorName", record.getDonorName());
            detail.put("gameNickname", record.getGameNickname());
            detail.put("amount", record.getAmount());
            detail.put("paymentStatus", record.getPaymentStatus());
            detail.put("donateDate", record.getDonateDate());
            recordDetails.add(detail);
        }
        debugInfo.put("allRecords", recordDetails);

        return debugInfo;
    }

    /**
     * 更新捐赠记录的支付状态
     * @param donationId 捐赠记录ID
     * @param paymentStatus 支付状态
     * @param paymentOrderId 支付订单号
     */
    @Transactional(readOnly = false)
    public void updatePaymentStatus(Long donationId, String paymentStatus, String paymentOrderId) {
        try {
            DonationRecord donation = new DonationRecord();
            donation.setId(donationId.toString());
            donation = dao.get(donation);

            if (donation != null) {
                donation.setPaymentStatus(paymentStatus);
                if (paymentOrderId != null) {
                    donation.setPaymentOrderId(paymentOrderId);
                }

                // 如果支付成功，设置支付时间
                if ("PAID".equals(paymentStatus)) {
                    donation.setDonateDate(new Date());
                }

                dao.update(donation);
                logger.info("捐赠记录支付状态已更新: ID={}, Status={}", donationId, paymentStatus);
            } else {
                logger.warn("未找到捐赠记录: ID={}", donationId);
            }
        } catch (Exception e) {
            logger.error("更新捐赠记录支付状态失败: ID=" + donationId, e);
            throw e;
        }
    }
}
